package com.henry.intercept;


import cn.hutool.core.util.ObjectUtil;
import com.henry.annotations.CryptHandlerClass;
import com.henry.annotations.EncryptFiled;
import com.henry.config.EncryptorConfig;
import com.henry.encryptor.Encryptor;
import com.henry.factory.EncryptorFactory;
import java.lang.reflect.Field;
import java.sql.PreparedStatement;
import java.util.Properties;
import lombok.AllArgsConstructor;
import org.apache.ibatis.executor.parameter.ParameterHandler;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.plugin.Intercepts;
import org.apache.ibatis.plugin.Invocation;
import org.apache.ibatis.plugin.Signature;
import org.springframework.stereotype.Component;

/**
 * 字段落库拦截加密处理
 *
 * @author Liu Hanlin
 * @create 2025-08-16 11:06
 */
@Component
@Intercepts(
        @Signature(type = ParameterHandler.class, method = "setParameters", args = PreparedStatement.class)
)
@AllArgsConstructor
public class EncryptFiledInterceptor implements Interceptor {

    private final EncryptorFactory encryptorFactory;

    private final EncryptorConfig encryptorConfig;


    /**
     * 该方法实现拦截处理，其实就是一个代理方法，当执行
     * ParameterHandler.class 的 setParameters(PreparedStatement preparedStatement)方法时
     * 会执行该方法，而且 setParameters 方法的信息也会被封装到 Invocation 参数中
     * @param invocation 封装
     * @return
     * @throws Throwable
     */
    @Override
    public Object intercept(Invocation invocation) throws Throwable {

        // 获取代理的目标类
        ParameterHandler parameterHandler  = (ParameterHandler) invocation.getTarget();

        Object parameterObject = parameterHandler.getParameterObject();

        // 获取执行insert/update/select/delete等操作的入参对象
        Class<?> parameter = parameterObject.getClass();

        if(ObjectUtil.isNotNull(parameter.getAnnotation(CryptHandlerClass.class))){

            Field[] fields = parameter.getDeclaredFields();
            for (Field field : fields) {

                field.setAccessible(true);
                if(ObjectUtil.isNotNull(field.getAnnotation(EncryptFiled.class))){
                    Encryptor encryptor = getEncryptorByType();
                    if(ObjectUtil.isNull(encryptor)){
                        throw new RuntimeException("加密工具类型不存在，请检查配置！");
                    }
                    String encryptPassword = encryptor.encrypt(field.get(parameterObject).toString(), encryptorConfig.getValue());
                    field.set(parameterObject, encryptPassword);
                }
            }

        }
        return invocation.proceed();

    }

    /**
     * 获取配置的加密类型
     *
     * @return 加密工具类
     */
    private Encryptor getEncryptorByType(){
        return encryptorFactory.getEncryptor(encryptorConfig.getType());
    }

    @Override
    public Object plugin(Object target) {
        return Interceptor.super.plugin(target);
    }

    @Override
    public void setProperties(Properties properties) {
        Interceptor.super.setProperties(properties);
    }
}
